package org.luxor.commons.jdbc.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.luxor.commons.jdbc.annotation.DS;
import org.luxor.commons.jdbc.plugin.dynamic.processor.DsProcessor;
import org.luxor.commons.jdbc.plugin.dynamic.toolkit.DynamicDataSourceContextHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

/**
 * 动态数据源切面类
 *
 * @author Mr.Yan  @date 2019/9/30
 */
@Aspect
@Order(Integer.MIN_VALUE)
public class DynamicDataSourceAspect {

    private Logger log = LoggerFactory.getLogger(DynamicDataSourceAspect.class);

    private DsProcessor dsProcessor;

    public DynamicDataSourceAspect(DsProcessor dsProcessor) {
        Assert.notNull(dsProcessor, "dsProcessor cannot be empty");
        this.dsProcessor = dsProcessor;
    }

    @Around("@within(org.luxor.commons.jdbc.annotation.DS)||@annotation(org.luxor.commons.jdbc.annotation.DS)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        try {
            String key = determineDatasource(point);
            DynamicDataSourceContextHolder.push(key);
            return point.proceed();
        } finally {
            DynamicDataSourceContextHolder.poll();
        }
    }

    private String determineDatasource(ProceedingJoinPoint pjp) {
        DS ds = null;

        Class<?> thisClass = pjp.getTarget().getClass();
        if (thisClass.isAnnotationPresent(DS.class)) {
            ds = thisClass.getAnnotation(DS.class);
        }

        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        if (method.isAnnotationPresent(DS.class)) {
            ds = method.getAnnotation(DS.class);
        }
        String key = dsProcessor.determineDatasource(pjp, ds.value());
        if (StringUtils.isEmpty(key)) {
            key = ds.value();
        }
        return key;
    }

}
